//////////////////////////////////////////////////////////////////////
//
//	Crytek CryENGINE Source code
// 
//	File: SystemRender.cpp
//  Description: CryENGINE system core 
// 
//	History:
//	-Jan 6,2004: split from system.cpp
//
//////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "System.h"
#include "IEntity.h"
#include "IStatoscope.h"
#include "IScaleformGFx.h"

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif












#include <IRenderer.h>
#include <IRenderAuxGeom.h>
#include <IProcess.h>
#include "Log.h"
#include "XConsole.h"
#include <I3DEngine.h>
#include <IAISystem.h>
#include <ISound.h>
#include <CryLibrary.h>
#include <IBudgetingSystem.h>
#include "PhysRenderer.h"
#include <IScriptSystem.h>
#include <IEntitySystem.h>
#include <IParticles.h>
#include <IMovieSystem.h>
#include <IScaleformGFx.h>

#include "CrySizerStats.h"
#include "CrySizerImpl.h"
#include "ITestSystem.h"							// ITestSystem
#include "VisRegTest.h"
#include "ThreadProfiler.h"
#include "IDiskProfiler.h"
#include "ITextModeConsole.h"
#include "HardwareMouse.h"
#include "../CryCommon/IEntitySystem.h"
#include "../CryAction/IActorSystem.h"

#include "MiniGUI/MiniGUI.h"
#include "PerfHUD.h"

extern CMTSafeHeap* g_pPakHeap;

#ifdef WIN32
#if defined(DIRECT3D9)
#include <ddraw.h>
#endif
extern HRESULT GetDXVersion( DWORD* pdwDirectXVersion, TCHAR* strDirectXVersion, int cchDirectXVersion );
#endif





// forward declare display function of EnginePropertyBlender debugger for use in CSystem::RenderStatistics(); a list of visitors maybe?
void RenderEnginePropertyBlenderInfo();

extern int CryMemoryGetAllocatedSize();

/////////////////////////////////////////////////////////////////////////////////
void CSystem::CreateRendererVars(const SSystemInitParams &startupParams)
{
	// load renderer settings from engine.ini
	m_rWidth = REGISTER_INT("r_Width", 1024, VF_DUMPTODISK,
		"Sets the display width, in pixels. Default is 1024.\n"
		"Usage: r_Width [800/1024/..]");
	m_rHeight = REGISTER_INT("r_Height", 768, VF_DUMPTODISK,
		"Sets the display height, in pixels. Default is 768.\n"
		"Usage: r_Height [600/768/..]");
	m_rColorBits = REGISTER_INT("r_ColorBits", 32, VF_DUMPTODISK,
		"Sets the color resolution, in bits per pixel. Default is 32.\n"
		"Usage: r_ColorBits [32/24/16/8]");
	m_rDepthBits = REGISTER_INT("r_DepthBits", 32, VF_DUMPTODISK,"");
	m_rStencilBits = REGISTER_INT("r_StencilBits", 8, VF_DUMPTODISK,"");
#if (defined(WIN32) || defined(WIN64))
	const char* p_r_DriverDef = "Auto";


#else
	const char* p_r_DriverDef = "DX9";							// required to be deactivated for final release
#endif
	if (startupParams.pCvarsDefault)
	{ // hack to customize the default value of r_Driver
		SCvarsDefault* pCvarsDefault = startupParams.pCvarsDefault;
		if (pCvarsDefault->sz_r_DriverDef && pCvarsDefault->sz_r_DriverDef[0])
			p_r_DriverDef = startupParams.pCvarsDefault->sz_r_DriverDef;
	}
	
	m_rDriver = REGISTER_STRING("r_Driver", p_r_DriverDef, VF_DUMPTODISK,
		"Sets the renderer driver ( DX9/DX11/AUTO/NULL ). Default is DX11 on Vista and Windows 7 and DX9 otherwise.\n"
		"Specify in system.cfg like this: r_Driver = \"DX11\"");

#if defined(WIN32) || defined(WIN64)
  // Temporary disabling DX11
  //m_rDriver->Set("DX9");
#endif

	int iFullScreenDefault = 1;
	int iDisplayInfoDefault = 0;

	if (IsDevMode())
	{
		iFullScreenDefault=0;
		iDisplayInfoDefault=1;
	}

	m_rFullscreen = REGISTER_INT("r_Fullscreen",iFullScreenDefault, VF_DUMPTODISK,
		"Toggles fullscreen mode. Default is 1 in normal game and 0 in DevMode.\n"
		"Usage: r_Fullscreen [0=window/1=fullscreen]");

	m_rFullscreenWindow = REGISTER_INT("r_FullscreenWindow",0, VF_DUMPTODISK,
		"Toggles fullscreen-as-window mode. Fills screen but allows seamless switching. Default is 0.\n"
		"Usage: r_FullscreenWindow [0=locked fullscreen/1=fullscreen as window]");

	m_rDisplayInfo = REGISTER_INT("r_DisplayInfo",iDisplayInfoDefault, VF_RESTRICTEDMODE|VF_DUMPTODISK,
		"Toggles debugging information display.\n"
		"Usage: r_DisplayInfo [0=off/1=show/2=enhanced]");
}

//////////////////////////////////////////////////////////////////////////
void CSystem::RenderBegin()
{
	FUNCTION_PROFILER_FAST( GetISystem(),PROFILE_SYSTEM,g_bProfilerEnabled );

	if (m_bIgnoreUpdates)
		return;

	bool rndAvail = m_env.pRenderer != 0;

	//////////////////////////////////////////////////////////////////////
	//start the rendering pipeline
	if (rndAvail)
	{
		m_env.pRenderer->BeginFrame();
	}

	gEnv->nMainFrameID = (rndAvail) ? m_env.pRenderer->GetFrameID(false) : 0;

#if !defined (EXCLUDE_SCALEFORM_SDK)
	if (rndAvail)
	{
		// render thread IDs might get updated in BeginFrame() so update GFx render layer
		if ( gEnv->pScaleformGFx )
		{
			uint32 mainThread = 0, renderThread = 0;
			m_env.pRenderer->GetThreadIDs(mainThread, renderThread);
			gEnv->pScaleformGFx->SetThreadIDs(mainThread, renderThread);
		}
	}
#endif
}

char *PhysHelpersToStr(int iHelpers, char *strHelpers);
int StrToPhysHelpers(const char *strHelpers);

//////////////////////////////////////////////////////////////////////////
void CSystem::RenderEnd( bool bRenderStats )
{
	{
		FUNCTION_PROFILER_FAST( GetISystem(),PROFILE_SYSTEM,g_bProfilerEnabled );

		if (m_bIgnoreUpdates)
			return;

		if (!m_env.pRenderer)
			return;

/*
		if(m_env.pMovieSystem)
			m_env.pMovieSystem->Render();
*/

		if(m_env.pGame)
			m_env.pGame->RenderGameWarnings();

		{
			// keep debug allocations out of level heap
			ScopedSwitchToGlobalHeap globalHeap;

#if !defined (_RELEASE)
		RenderPhysicsHelpers();

		if (m_env.pRenderer->GetIRenderAuxGeom())
			m_env.pRenderer->GetIRenderAuxGeom()->Flush();
#endif

#if !defined (_RELEASE)
		// Flush render data and swap buffers.
		m_env.pRenderer->RenderDebug(bRenderStats);
#endif

		RenderPS3Stats(bRenderStats);

#if defined(USE_PERFHUD)
		if (m_pPerfHUD)
			m_pPerfHUD->Draw();
		if (m_pMiniGUI)
			m_pMiniGUI->Draw();
#endif

#if !defined (_RELEASE)
		if (m_env.p3DEngine)
		m_env.p3DEngine->DrawDeferredCoverageBufferDebug();
#endif

		if (bRenderStats)
		{
			RenderStatistics();
		}


		if (IConsole* pConsole = GetIConsole())
			pConsole->Draw();
		}

	//#ifndef WIN32
		//if(gEnv && gEnv->pHardwareMouse)
			//static_cast<CHardwareMouse *>(gEnv->pHardwareMouse)->Render();
	//#endif

		gEnv->GetJobManager()->AddStartMarker("WaitForRenderThread", eTI_WaitForRenderThread);
		m_env.pRenderer->EndFrame();
		m_env.pRenderer->ForceGC();
		gEnv->GetJobManager()->AddStopMarker(eTI_WaitForRenderThread);




#if !defined(XENON) && !defined(PS3)
    if (IConsole* pConsole = GetIConsole())
    {
      // if we have pending cvar calculation, execute it here
      // since we know cvars will be correct here after ->EndFrame().
			if(!pConsole->IsHashCalculated())
				pConsole->CalcCheatVarHash();
    }
#endif

#if !defined (_RELEASE)
#if ENABLE_STATOSCOPE
		if(gEnv->pStatoscope)
		{
			gEnv->pStatoscope->SetCurrentTexturePoolAllocations(gEnv->pRenderer->GetTexturePoolAllocationList());
		}
#endif	// ENABLE_STATOSCOPE
		gEnv->pRenderer->ClearTexturePoolAllocationList();
#endif
	}

#if defined(ENABLE_PROFILING_CODE)
	gEnv->bProfilerEnabled = m_sys_profile->GetIVal() != 0;
#endif
}

//////////////////////////////////////////////////////////////////////////
void CSystem::RenderPhysicsHelpers()
{
#if !defined(_RELEASE)
	//////////////////////////////////////////////////////////////////////
	// draw physics helpers
	if (m_env.pPhysicalWorld)
	{
		ITextModeConsole * pTMC = GetITextModeConsole();

		char str[32];
		if (StrToPhysHelpers(m_p_draw_helpers_str->GetString()) != m_env.pPhysicalWorld->GetPhysVars()->iDrawHelpers)
			m_p_draw_helpers_str->Set(PhysHelpersToStr(m_env.pPhysicalWorld->GetPhysVars()->iDrawHelpers,str));
		m_PhysRendererCamera = GetViewCamera();
		m_PhysRendererCamera.SetFrustum(GetViewCamera().GetViewSurfaceX(), GetViewCamera().GetViewSurfaceZ(),
			GetViewCamera().GetFov(), GetViewCamera().GetNearPlane(), m_pPhysRenderer->m_cullDist, GetViewCamera().GetPixelAspectRatio());
		m_env.pPhysicalWorld->DrawPhysicsHelperInformation(m_pPhysRenderer);
		m_pPhysRenderer->DrawBuffers(m_Time.GetFrameTime());

		phys_profile_info *pInfos;
		phys_job_info *pJobInfos; 
		PhysicsVars *pVars;
		int i=-2;
		char msgbuf[512];
		if ((pVars=m_env.pPhysicalWorld->GetPhysVars())->bProfileEntities)
		{
			pe_status_pos sp;
			int j,mask,nEnts = m_env.pPhysicalWorld->GetEntityProfileInfo(pInfos);
			float fColor[4] = { 0.3f,0.6f,1.0f,1.0f }, dt;
			if (!pVars->bSingleStepMode) {
				for(i=0;i<nEnts;i++) {
					pInfos[i].nTicksAvg = (int)(((int64)pInfos[i].nTicksAvg*15+pInfos[i].nTicksLast)>>4);
					pInfos[i].nCallsAvg = pInfos[i].nCallsAvg*(15.0f/16)+pInfos[i].nCallsLast*(1.0f/16);
				}
				phys_profile_info ppi;
				for(i=0;i<nEnts-1;i++) for(j=nEnts-1;j>i;j--) if (pInfos[j-1].nTicksAvg<pInfos[j].nTicksAvg) {
					ppi=pInfos[j-1]; pInfos[j-1]=pInfos[j]; pInfos[j]=ppi;
				}
			}
			for(i=0;i<nEnts;i++) {
				mask = (pInfos[i].nTicksPeak-pInfos[i].nTicksLast) >> 31;
				mask |= (70-pInfos[i].peakAge)>>31;
				mask &= (pVars->bSingleStepMode-1)>>31;
				pInfos[i].nTicksPeak += pInfos[i].nTicksLast-pInfos[i].nTicksPeak & mask;
				pInfos[i].nCallsPeak += pInfos[i].nCallsLast-pInfos[i].nCallsPeak & mask;
				sprintf(msgbuf, "%.2fms/%.1f (peak %.2fms/%d) %s (id %d)",
					dt = gEnv->pTimer->TicksToSeconds(pInfos[i].nTicksAvg*1024)*1000.0f, pInfos[i].nCallsAvg, 
					gEnv->pTimer->TicksToSeconds(pInfos[i].nTicksPeak*1024)*1000.0f, pInfos[i].nCallsPeak, 
					pInfos[i].pName, pInfos[i].id);
				GetIRenderer()->Draw2dLabel( 10.0f,60.0f+i*12.0f, 1.3f, fColor,false, "%s", msgbuf );
				if (pTMC) pTMC->PutText( 0, i, msgbuf );
				IPhysicalEntity *pent = m_env.pPhysicalWorld->GetPhysicalEntityById(pInfos[i].id);
				if (dt>0.1f && pent && pent->GetStatus(&sp))
					GetIRenderer()->DrawLabelEx(sp.pos+Vec3(0,0,sp.BBox[1].z), 1.4f,fColor,true,true, "%s %.2fms", pInfos[i].pName,dt);
				pInfos[i].peakAge = pInfos[i].peakAge+1 & ~mask;
				//pInfos[i].nCalls=pInfos[i].nTicks = 0;
			}

			if (inrange(m_iJumpToPhysProfileEnt,0,nEnts+1))
			{
				ScriptHandle hdl;	hdl.n=~0;
				m_env.pScriptSystem->GetGlobalValue("g_localActorId",hdl);
				IEntity *pPlayerEnt = m_env.pEntitySystem->GetEntity((EntityId)hdl.n);
				IPhysicalEntity *pent = m_env.pPhysicalWorld->GetPhysicalEntityById(pInfos[m_iJumpToPhysProfileEnt-1].id);
				if (pPlayerEnt && pent) {
					pe_params_bbox pbb; pent->GetParams(&pbb);
					pPlayerEnt->SetPos((pbb.BBox[0]+pbb.BBox[1])*0.5f+Vec3(0,-3.0f,1.5f));
					pPlayerEnt->SetRotation(Quat(IDENTITY));
				}
				m_iJumpToPhysProfileEnt = 0;
			}
		}
		if (pVars->bProfileFunx)
		{
			int j,mask,nFunx = m_env.pPhysicalWorld->GetFuncProfileInfo(pInfos);
			float fColor[4] = { 0.75f,0.08f,0.85f,1.0f };
			for(j=0,++i;j<nFunx;j++,i++) {
				mask = (pInfos[j].nTicksPeak-pInfos[j].nTicks) >> 31;
				mask |= (70-pInfos[j].peakAge)>>31;
				pInfos[j].nTicksPeak += pInfos[j].nTicks-pInfos[j].nTicksPeak & mask;
				pInfos[j].nCallsPeak += pInfos[j].nCalls-pInfos[j].nCallsPeak & mask;
				GetIRenderer()->Draw2dLabel( 10.0f,60.0f+i*12.0f, 1.3f, fColor,false,
					"%s %.2fms/%d (peak %.2fms/%d)", pInfos[j].pName, gEnv->pTimer->TicksToSeconds(pInfos[j].nTicks*1024)*1000.0f, pInfos[j].nCalls,
					gEnv->pTimer->TicksToSeconds(pInfos[j].nTicksPeak*1024)*1000.0f, pInfos[j].nCallsPeak);
				pInfos[j].peakAge = pInfos[j].peakAge+1 & ~mask;
				pInfos[j].nCalls=pInfos[j].nTicks = 0;
			}
		}
		if (pVars->bProfileGroups)
		{
			int j=0,mask,nGroups=m_env.pPhysicalWorld->GetGroupProfileInfo(pInfos), nJobs=m_env.pPhysicalWorld->GetJobProfileInfo(pJobInfos);
			float fColor[4] = { 1.0f,1.0f,1.0f,1.0f };
			if (!pVars->bProfileEntities)
				j = 12;

			for(++i;j<nGroups;j++,i++) {
				pInfos[j].nTicksAvg = (int)(((int64)pInfos[j].nTicksAvg*15+pInfos[j].nTicksLast)>>4);
				mask = (pInfos[j].nTicksPeak-pInfos[j].nTicksLast) >> 31;
				mask |= (70-pInfos[j].peakAge)>>31;
				pInfos[j].nTicksPeak += pInfos[j].nTicksLast-pInfos[j].nTicksPeak & mask;
				pInfos[j].nCallsPeak += pInfos[j].nCallsLast-pInfos[j].nCallsPeak & mask;
				float time = gEnv->pTimer->TicksToSeconds(pInfos[j].nTicksAvg*1024)*1000.0f;



				float timeNorm = time*(1.0f/32);

				fColor[1]=fColor[2] = 1.0f-(max(0.7f,min(1.0f,timeNorm))-0.7f)*(1.0f/0.3f);
				GetIRenderer()->Draw2dLabel( 10.0f,60.0f+i*12.0f, 1.3f, fColor,false,
					"%s %.2fms/%d (peak %.2fms/%d)", pInfos[j].pName, time,pInfos[j].nCallsLast, 
					gEnv->pTimer->TicksToSeconds(pInfos[j].nTicksPeak*1024)*1000.0f, pInfos[j].nCallsPeak);
				pInfos[j].peakAge = pInfos[j].peakAge+1 & ~mask;
				if (j==10) ++i;
			}













































		}
			}
#endif
}

//////////////////////////////////////////////////////////////////////////
void CSystem::RenderPS3Stats( bool bRenderStats )
{
	//enable job system filtering to disable async execution at runtime
	const char* const cpFilterName = m_sys_job_system_filter->GetString();
	if(cpFilterName && *cpFilterName != 0 && *cpFilterName != '0')
	{
		gEnv->GetJobManager()->SetJobFilter(cpFilterName);		
	}
	else
	{
		gEnv->GetJobManager()->SetJobFilter(NULL);
	}

	gEnv->GetJobManager()->Update(m_sys_job_system_profiler->GetIVal());
	gEnv->GetJobManager()->SetJobSystemEnabled(m_sys_job_system_enable->GetIVal());	





































































































}

//! Update screen and call some important tick functions during loading.
void CSystem::SynchronousLoadingTick()
{
	LOADING_TIME_PROFILE_SECTION;
	if( gEnv && gEnv->bMultiplayer && !gEnv->IsEditor() )
	{
		//UpdateLoadingScreen currently contains a couple of tick functions that need to be called regularly during the synchronous level loading,
		//when the usual engine and game ticks are suspended.
		//Examples include the minimal Network tick and PS3 cellSysUtil queue checking to meet essential TRCs
		UpdateLoadingScreen();

		SLICE_AND_SLEEP();
	}
}





//////////////////////////////////////////////////////////////////////////
//#define CHECK_UPDATE_TIMES
void CSystem::UpdateLoadingScreen()
{
	// Do not update the network thread from here - it will cause context corruption - use the NetworkStallTicker thread system

	if ( GetCurrentThreadId() != gEnv->mMainThreadId )
	{
		return;
	}
		
	// Take this opportunity to update streaming engine.
	static CTimeValue t0;
	CTimeValue t = gEnv->pTimer->GetAsyncTime();
	float timeDelta = fabs((t-t0).GetSeconds()); 
	if( timeDelta < 1.0f )	// Update screen not frequent,not more than once in 1 second
	{
		return;
	}
#if defined(CHECK_UPDATE_TIMES)
	else if( timeDelta > 5.0f )
	{
		CryWarning( VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "CSystem::UpdateLoadingScreen (eNGS_MinimalUpdateForLoading) %f seconds since last tick: this is a long delay for loading MP and a serious risk for failing PS3 TRC R076\n", timeDelta );
	}
	else if( timeDelta > 1.5f )
	{
		CryWarning( VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "CSystem::UpdateLoadingScreen (eNGS_MinimalUpdateForLoading) %f seconds since last tick: this is a moderate delay for loading MP and a moderate risk for failing PS3 TRC R076\n", timeDelta );
	}
#endif
	t0 = t;

	if (!m_bEditor && !m_bQuit)
	{
		if (m_pProgressListener)
		{
			m_pProgressListener->OnLoadingProgress(0);
		}









		if ((int)GetIRenderer()->EF_Query(EFQ_RecurseLevel) == 0 &&
			(int)GetIRenderer()->EF_Query(EFQ_DeviceLost) != 0)
		{
			if (m_env.pConsole->IsOpened())
			{
				RenderBegin();
				GetIConsole()->Draw();
				RenderEnd();
			}
		}
	}
	// This happens during loading, give windows opportunity to process window messages.
#ifdef WIN32
	{
		if (!m_bQuit && m_hWnd && ::IsWindow((HWND)m_hWnd))
		{
			MSG msg;
			// Don't make any steps while 3D device is lost
			//while (true)
			{
				// Must be PeekMessageW for Scaleform IME to function correctly and to ensure WM_CHAR contains
				// Unicode widechar for languages like Russian
				while (PeekMessageW(&msg, (HWND)m_hWnd, 0, 0, PM_REMOVE))
				{
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
				//int *nLost = (int *)GetIRenderer()->EF_Query(EFQ_DeviceLost, 0);
				//if (!*nLost)
				//  break;
			}
		}
	}

#endif
















}

//////////////////////////////////////////////////////////////////////////

void CSystem::DisplayErrorMessage(const char* acMessage, 
																	float fTime, 
																	const float* pfColor, 
																	bool bHardError)
{
	ScopedSwitchToGlobalHeap useGlobalHeap;

	SErrorMessage message;
	message.m_Message = acMessage;
	if (pfColor) {
		memcpy(message.m_Color, pfColor, 4 * sizeof(float));
	} else {
		message.m_Color[0] = 1.0f;
		message.m_Color[1] = 0.0f;
		message.m_Color[2] = 0.0f;
		message.m_Color[3] = 1.0f;
	}
	message.m_HardFailure = bHardError;
#ifdef _RELEASE
	message.m_fTimeToShow = fTime;
#else
	message.m_fTimeToShow = 1.0f;
#endif
	m_ErrorMessages.push_back(message);
}

//! Renders the statistics; this is called from RenderEnd, but if the 
//! Host application (Editor) doesn't employ the Render cycle in ISystem,
//! it may call this method to render the essential statistics
//////////////////////////////////////////////////////////////////////////
void CSystem::RenderStatistics ()
{
	RenderStats();
#if !defined(_RELEASE)
	// Render profile info.
	m_FrameProfileSystem.Render();
	if (m_pThreadProfiler)
		m_pThreadProfiler->Render();
#ifdef USE_DISK_PROFILER
	if (m_pDiskProfiler)
		m_pDiskProfiler->Update();
#endif
	
	RenderMemStats();

	if (m_sys_profile_sampler->GetIVal() > 0)
	{
		m_sys_profile_sampler->Set(0);
		m_FrameProfileSystem.StartSampling( m_sys_profile_sampler_max_samples->GetIVal() );
	}

	// Update frame profiler from sys variable: 1 = enable and display, -1 = just enable
	int profValue = m_sys_profile->GetIVal();
	static int prevProfValue = -100;
	bool bEnable = profValue != 0,
		   bDisplay = profValue > 0;
	if (prevProfValue != profValue)
	{
		prevProfValue = profValue;
		int dispNum = abs(profValue);
		m_FrameProfileSystem.SetDisplayQuantity( (CFrameProfileSystem::EDisplayQuantity)(dispNum-1) );
	}
	if (bEnable != m_FrameProfileSystem.IsEnabled() || bDisplay != m_FrameProfileSystem.IsVisible())
	{
		m_FrameProfileSystem.Enable(bEnable, bDisplay);
	}
	if (m_FrameProfileSystem.IsEnabled())
	{
		static string sSysProfileFilter;
		if (stricmp(m_sys_profile_filter->GetString(),sSysProfileFilter.c_str()) != 0)
		{
			sSysProfileFilter = m_sys_profile_filter->GetString();
			m_FrameProfileSystem.SetSubsystemFilter( sSysProfileFilter.c_str() );
		}
		static string sSysProfileFilterThread;
		if (0 != sSysProfileFilterThread.compare(m_sys_profile_filter_thread->GetString()))
		{
			sSysProfileFilterThread = m_sys_profile_filter_thread->GetString();
			m_FrameProfileSystem.SetSubsystemFilterThread( sSysProfileFilterThread.c_str() );
			m_sys_profile_allThreads->Set(1);
		}
		m_FrameProfileSystem.SetHistogramScale( m_sys_profile_graphScale->GetFVal() );
		m_FrameProfileSystem.SetDrawGraph( m_sys_profile_graph->GetIVal() != 0 );
		m_FrameProfileSystem.SetThreadSupport( m_sys_profile_allThreads->GetIVal() );
		m_FrameProfileSystem.SetNetworkProfiler( m_sys_profile_network->GetIVal() != 0 );
		m_FrameProfileSystem.SetPeakTolerance( m_sys_profile_peak->GetFVal() );
		m_FrameProfileSystem.SetPageFaultsGraph( m_sys_profile_pagefaultsgraph->GetIVal() != 0 );
		m_FrameProfileSystem.SetPeakDisplayDuration(m_sys_profile_peak_time->GetFVal());
		m_FrameProfileSystem.SetAdditionalSubsystems(m_sys_profile_additionalsub->GetIVal() != 0);
	}
	static int memProfileValueOld = 0;
	int memProfileValue = m_sys_profile_memory->GetIVal();
	if (memProfileValue != memProfileValueOld)
	{
		memProfileValueOld = memProfileValue;
		m_FrameProfileSystem.EnableMemoryProfile( memProfileValue!=0 );
	}
#endif
	if ( gEnv->pScaleformGFx && gEnv->pScaleformGFx->IsScaleformSupported() )
	{
		gEnv->pScaleformGFx->RenderFlashInfo();
	}
#if !defined(_RELEASE)
	RenderEnginePropertyBlenderInfo();

	if(m_sys_enable_budgetmonitoring->GetIVal())
		m_pIBudgetingSystem->MonitorBudget();
#endif
}

//////////////////////////////////////////////////////////////////////
void CSystem::Render()
{
	if (m_bIgnoreUpdates)
		return;

	//check what is the current process 
	if (!m_pProcess)
		return; //should never happen

	//check if the game is in pause or
	//in menu mode
	//bool bPause=false;
	//if (m_pProcess->GetFlags() & PROC_MENU)
	//	bPause=true;

	FUNCTION_PROFILER_FAST( GetISystem(),PROFILE_SYSTEM,g_bProfilerEnabled );

	//////////////////////////////////////////////////////////////////////
	//draw	
  if (m_pProcess && (m_pProcess->GetFlags() & PROC_3DENGINE))
  {	
		if( !gEnv->IsEditing() ) // Editor calls it's own rendering update
		{

#if !defined(_RELEASE)
			if(m_pTestSystem)
				m_pTestSystem->BeforeRender();
#endif

			if (m_env.p3DEngine && !m_env.IsFMVPlaying())
				if (!IsEquivalent(m_ViewCamera.GetPosition(),Vec3(0,0,0),VEC_EPSILON) || // never pass undefined camera to p3DEngine->RenderWorld()
						gEnv->IsDedicated() ||
						(gEnv->pRenderer && gEnv->pRenderer->IsPost3DRendererEnabled())) 
			{
				GetIRenderer()->SetViewport(0,0,GetIRenderer()->GetWidth(),GetIRenderer()->GetHeight());
				m_env.p3DEngine->RenderWorld(SHDF_ALLOW_WATER|SHDF_ALLOWPOSTPROCESS | SHDF_ALLOWHDR | SHDF_ZPASS | SHDF_ALLOW_AO, &m_ViewCamera, 1, __FUNCTION__);
			} 
			else
			{
				if (gEnv->pRenderer)
				{
					// force rendering of black screen to be sure we don't only render the clear color (which is the fog color by default)
					gEnv->pRenderer->SetState(GS_BLSRC_SRCALPHA|GS_BLDST_ONEMINUSSRCALPHA|GS_NODEPTHTEST);
					gEnv->pRenderer->Draw2dImage(0, 0, 800, 600, -1, 0.0f,0.0f,1.0f,1.0f,	0.f,
						0.0f, 0.0f, 0.0f, 1.0f, 0.f);
				}
			}

#if !defined(_RELEASE)
			if( m_pVisRegTest )
				m_pVisRegTest->AfterRender();
			if(m_pTestSystem)
				m_pTestSystem->AfterRender();

			//			m_pProcess->Draw();		
						
			if (m_env.pEntitySystem)		
				m_env.pEntitySystem->DebugDraw();

			if (m_env.pAISystem)		
				m_env.pAISystem->DebugDraw();
#endif

			if (m_env.pMovieSystem)		
				m_env.pMovieSystem->Render();
		}
  }
  else
  {
    if (m_pProcess)	
		{
			GetIRenderer()->SetViewport(0,0,GetIRenderer()->GetWidth(),GetIRenderer()->GetHeight());
      m_pProcess->RenderWorld(SHDF_ALLOW_WATER |SHDF_ALLOWPOSTPROCESS | SHDF_ALLOWHDR | SHDF_ZPASS | SHDF_ALLOW_AO, &m_ViewCamera, 1, __FUNCTION__);		
		}
  }
}

//////////////////////////////////////////////////////////////////////////
void CSystem::RenderMemStats()
{
#if !defined(_RELEASE)
	// check for the presence of the system
	if (!m_env.pConsole || !m_env.pRenderer || !m_cvMemStats->GetIVal())
	{
		SAFE_DELETE(m_pMemStats);
		return;
	}

	TickMemStats();

	assert (m_pMemStats);
	m_pMemStats->updateKeys();
	// render the statistics
	{
		CrySizerStatsRenderer StatsRenderer (this, m_pMemStats, m_cvMemStatsMaxDepth->GetIVal(), m_cvMemStatsThreshold->GetIVal());
		StatsRenderer.render((m_env.pRenderer->GetFrameID(false)+2)%m_cvMemStats->GetIVal() <= 1);
	}
#endif

}

//////////////////////////////////////////////////////////////////////////
void CSystem::RenderStats()
{

#if defined(ENABLE_PROFILING_CODE)
#ifndef _RELEASE
	// if we rendered an error message on screen during the last frame, then sleep now
	// to force hard stall for 3sec
	if (m_bHasRenderedErrorMessage && !gEnv->IsEditor())
	{
		Sleep(3000);
		m_bHasRenderedErrorMessage = false;
	}
#endif

	// render info messages on screen
	float fTextPosX = 5.0f;
	float fTextPosY = -10;
	float fTextStepY = 13;

	//take overscan borders into account
	Vec2 overscanBorders = *(Vec2*)m_env.pRenderer->EF_Query(EFQ_OverscanBorders);
	fTextPosX += ((float)m_env.pRenderer->GetWidth()) * overscanBorders.x;
	fTextPosY += ((float)m_env.pRenderer->GetHeight()) * overscanBorders.y;

	float fFrameTime = gEnv->pTimer->GetRealFrameTime();
	TErrorMessages::iterator itnext;
	for (TErrorMessages::iterator it = m_ErrorMessages.begin(); it != m_ErrorMessages.end(); it = itnext)
	{
		itnext = it; ++itnext;
		SErrorMessage& message = *it;

		SDrawTextInfo ti;
		ti.flags = eDrawText_FixedSize | eDrawText_2D | eDrawText_Monospace;
		memcpy(ti.color, message.m_Color, 4 * sizeof(float));
		ti.xscale = ti.yscale = 1.4f;
		m_env.pRenderer->DrawTextQueued( Vec3(fTextPosX, fTextPosY+=fTextStepY, 1.0f), ti, message.m_Message.c_str() );

		message.m_fTimeToShow -= fFrameTime;
		if (message.m_fTimeToShow < 0.0f)	{
			m_ErrorMessages.erase(it);
			continue;
		}

		if (message.m_HardFailure)
			m_bHasRenderedErrorMessage = true;
	}
#endif

	if (!m_env.pConsole)
		return;

	int iDisplayInfo = m_rDisplayInfo->GetIVal();
	if (iDisplayInfo == 0)
		return;

	// Draw engine stats
	if (m_env.p3DEngine)
  {
    // Draw 3dengine stats and get last text cursor position
    float nTextPosX=101-20, nTextPosY=-2, nTextStepY=3;
    m_env.p3DEngine->DisplayInfo(nTextPosX, nTextPosY, nTextStepY,iDisplayInfo!=1);		

#if defined(ENABLE_LW_PROFILERS)
	  if (m_rDisplayInfo->GetIVal()==2)
	  {
		  m_env.pRenderer->TextToScreen( nTextPosX, nTextPosY+=nTextStepY, "SysMem %.1f mb",  
        float(DumpMMStats(NULL))/1024.f);

			if (m_env.pSoundSystem)
			{
				SSoundMemoryInfo SoundMemInfo;
				m_env.pSoundSystem->GetInterfaceExtended()->GetMemoryInfo(&SoundMemInfo);	
				m_env.pRenderer->TextToScreen( nTextPosX-18, nTextPosY+=nTextStepY, "------------Sound %2.1f/%2.1f mb",
					SoundMemInfo.fSoundBucketPoolUsedInMB + SoundMemInfo.fSoundPrimaryPoolUsedInMB + SoundMemInfo.fSoundSecondaryPoolUsedInMB, 
					/*SoundMemInfo.fSoundBucketPoolSizeInMB +*/ SoundMemInfo.fSoundPrimaryPoolSizeInMB + SoundMemInfo.fSoundSecondaryPoolSizeInMB);
			}
	  }
#endif










  }
}

